package com.ushine.web.base.facade.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ushine.web.base.facade.IUserRolePermissionFacade;
import com.ushine.web.base.model.relation.UserAndRoleDO;
import com.ushine.web.base.model.relation.UserAndUserGroupDO;
import com.ushine.web.base.model.relation.UserGroupAndRoleDO;
import com.ushine.web.base.model.system.*;
import com.ushine.web.base.service.*;
import com.ushine.web.base.util.TreeAssemblyUtils;
import com.ushine.web.component.contant.BusinessConstant;
import com.ushine.web.component.contant.SysConstant;
import com.ushine.web.component.exception.LoginErrorEnum;
import com.ushine.web.component.exception.ServiceException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: yls
 * @Date 2022/2/17 11:14
 * @Description: 用户的权限、角色查询
 * @Version 1.0
 **/
@Service
@Transactional(rollbackFor = Exception.class)
public class UserRolePermissionFacadeImpl implements IUserRolePermissionFacade {
    @Resource
    private IRoleService roleService;

    @Resource
    private IUserAndRoleService userAndRoleService;

    @Resource
    private IUserService userService;

    @Resource
    private IUserAndUserGroupService userAndUserGroupService;

    @Resource
    private IUserGroupService userGroupService;

    @Resource
    private IUserGroupAndRoleService userGroupAndRoleService;

    @Resource
    private IFunctionPermissionService permissionService;

    @Resource
    private IDataPermissionService dataPermissionService;

    @Resource
    private TreeAssemblyUtils treeAssemblyUtils;

    @Override
    @Transactional(readOnly = true)
    public List<RoleDO> listUserRoles(Long userId, Set<Long> userGroupIds) {
        Set<Long> userGroupRoleIds = new HashSet<>();
        if (userGroupIds != null && !userGroupIds.isEmpty()) {
            // 获取用户组关联的角色
            LambdaQueryWrapper<UserGroupAndRoleDO> userGroupAndRoleQueryWrapper = new LambdaQueryWrapper<>();
            userGroupAndRoleQueryWrapper.in(UserGroupAndRoleDO::getUserGroupId, userGroupIds);
            List<UserGroupAndRoleDO> userGroupAndRoles = userGroupAndRoleService.list(userGroupAndRoleQueryWrapper);
            userGroupAndRoles = Optional.ofNullable(userGroupAndRoles).orElse(new ArrayList<>(0));
            userGroupRoleIds = userGroupAndRoles.stream().map(UserGroupAndRoleDO::getRoleId).collect(Collectors.toSet());

        }
        // 获取用户关联的角色
        LambdaQueryWrapper<UserAndRoleDO> userAndRoleQueryWrapper = new LambdaQueryWrapper<>();
        userAndRoleQueryWrapper.eq(UserAndRoleDO::getUserId, userId)
                .select(UserAndRoleDO::getRoleId);
        List<UserAndRoleDO> userRoles = userAndRoleService.list(userAndRoleQueryWrapper);
        userRoles = Optional.ofNullable(userRoles).orElse(new ArrayList<>(0));
        Set<Long> userRoleIds = userRoles.stream().map(UserAndRoleDO::getRoleId).collect(Collectors.toSet());
        //获取用户的角色
        userRoleIds.addAll(userGroupRoleIds);
        userRoleIds.add(0L);
        LambdaQueryWrapper<RoleDO> roleQueryWrapper = new LambdaQueryWrapper<>();
        roleQueryWrapper.in(RoleDO::getId, userRoleIds)
                .select(RoleDO::getId,
                        RoleDO::getName);
        List<RoleDO> roleList = roleService.list(roleQueryWrapper);
        roleList = Optional.ofNullable(roleList).orElse(new ArrayList<>(0));
        return roleList;
    }

    @Override
    @Transactional(readOnly = true)
    public UserDO listUserPermissions(Long userId) throws ServiceException {
        UserDO user = getUserRoleAndGroup(userId);
        List<RoleDO> roles = user.getRoles();
        roles = Optional.ofNullable(roles).orElse(new ArrayList<>(0));
        Set<Long> roleIds = roles.stream().map(RoleDO::getId).collect(Collectors.toSet());
        List<FunctionPermissionDO> permissons = permissionService.listPermissonsByRoleIds(roleIds);
        user.setFunctionPermissions(permissons);
        return user;
    }

    @Override
    @Transactional(readOnly = true)
    public UserDO listUserDataPermissions(Long userId) throws ServiceException {
        UserDO user = getUserRoleAndGroup(userId);
        List<RoleDO> roles = user.getRoles();
        roles = Optional.ofNullable(roles).orElse(new ArrayList<>(0));
        Set<Long> roleIds = roles.stream().map(RoleDO::getId).collect(Collectors.toSet());
        List<DataPermissionDO> dataPermissions = dataPermissionService.listDataPermissionsByRoleIds(roleIds);
        user.setDataPermissions(dataPermissions);
        return user;
    }

    @Override
    @Transactional(readOnly = true)
    public UserDO listUserAllPermissions(Long userId) throws ServiceException {
        UserDO user = getUserRoleAndGroup(userId);
        if (user == null) {
            throw new ServiceException(LoginErrorEnum.USER_ACCOUNT_NOT_EXIST);
        }
        List<RoleDO> roles = user.getRoles();
        roles = Optional.ofNullable(roles).orElse(new ArrayList<>(0));
        Set<Long> roleIds = roles.stream().map(RoleDO::getId).collect(Collectors.toSet());
        if (!roleIds.isEmpty()) {
            List<FunctionPermissionDO> permissons = permissionService.listPermissonsByRoleIds(roleIds);
            user.setFunctionPermissions(permissons);
            List<DataPermissionDO> dataPermissions = dataPermissionService.listDataPermissionsByRoleIds(roleIds);
            user.setDataPermissions(dataPermissions);
        }
        return user;
    }

    @Override
    @Transactional(readOnly = true)
    public UserDO listUserAllPermissions(String username) throws ServiceException {
        UserDO user = getUserRoleAndGroup(username);
        List<RoleDO> roles = user.getRoles();
        roles = Optional.ofNullable(roles).orElse(new ArrayList<>(0));
        Set<Long> roleIds = roles.stream().map(RoleDO::getId).collect(Collectors.toSet());
        if (!roleIds.isEmpty()) {
            List<FunctionPermissionDO> permissons = permissionService.listPermissonsByRoleIds(roleIds);
            user.setFunctionPermissions(permissons);
            List<DataPermissionDO> dataPermissions = dataPermissionService.listDataPermissionsByRoleIds(roleIds);
            user.setDataPermissions(dataPermissions);
        }
        return user;
    }

    @Override
    @Transactional(readOnly = true)
    public UserDO getUserRoleAndGroup(String userName) throws ServiceException {
        LambdaQueryWrapper<UserDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserDO::getUsername, userName)
//                .select(UserDO.class, field -> !"password".equals(field.getColumn()))
                .last(BusinessConstant.LIMIT_ONE);
        return getUserByQueryWrapper(queryWrapper);
    }

    @Override
    @Transactional(readOnly = true)
    public UserDO getUserRoleAndGroup(Long id) throws ServiceException {
        LambdaQueryWrapper<UserDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserDO::getId, id)
//                .select(UserDO.class, field -> !"password".equals(field.getColumn()))
                .last(BusinessConstant.LIMIT_ONE);
        return getUserByQueryWrapper(queryWrapper);
    }

    @Override
    @Transactional(readOnly = true)
    public List<UserGroupDO> listUserGroups(Long userId) {
        // 用户组关联关系
        LambdaQueryWrapper<UserAndUserGroupDO> userAndUserGroupQueryWrapper = new LambdaQueryWrapper<>();
        userAndUserGroupQueryWrapper.eq(UserAndUserGroupDO::getUserId, userId)
                .select(UserAndUserGroupDO::getUserId, UserAndUserGroupDO::getUserGroupId);
        List<UserAndUserGroupDO> userAndUserGroups = userAndUserGroupService.list(userAndUserGroupQueryWrapper);
        userAndUserGroups = Optional.ofNullable(userAndUserGroups).orElse(new ArrayList<>(0));
        Set<Long> userAndUserGroupIds = userAndUserGroups.stream().map(UserAndUserGroupDO::getUserGroupId).collect(Collectors.toSet());
        userAndUserGroupIds.add(0L);
        //获取用户组
        LambdaQueryWrapper<UserGroupDO> userGroupQueryWrapper = new LambdaQueryWrapper<>();
        userGroupQueryWrapper.in(UserGroupDO::getId, userAndUserGroupIds)
                .select(UserGroupDO::getId, UserGroupDO::getUserGroupName);
        List<UserGroupDO> userGroupList = userGroupService.list(userGroupQueryWrapper);
        userGroupList = Optional.ofNullable(userGroupList).orElse(new ArrayList<>(0));
        return userGroupList;
    }

    /**
     * 功能描述:
     * 〈 组装用户角色和权限 〉
     *
     * @param queryWrapper 用户角色
     * @return : com.ushine.web.base.model.system.UserDO
     * @author : yls
     * @date : 2022/2/17 11:26
     */
    private UserDO getUserByQueryWrapper(LambdaQueryWrapper<UserDO> queryWrapper) throws ServiceException {
        UserDO user = userService.getOne(queryWrapper);
        if (user == null) {
            throw new ServiceException(LoginErrorEnum.USER_ACCOUNT_NOT_EXIST);
        }
        // 获取用户的用户组
        List<UserGroupDO> userGroups = listUserGroups(user.getId());
        user.setUserGroups(userGroups);
        // 获取角色
        Set<Long> userGroupIds = userGroups.stream().map(UserGroupDO::getId).collect(Collectors.toSet());
        List<RoleDO> roles = listUserRoles(user.getId(), userGroupIds);
        user.setRoles(roles);
        return user;
    }


    @Override
    @Transactional(readOnly = true)
    public List<FunctionPermissionDO> listUserPermissionsTree(Long userId) throws ServiceException {
        LambdaQueryWrapper<UserDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserDO::getId, userId)
                .select(UserDO.class, field -> !"password".equals(field.getColumn()))
                .last(BusinessConstant.LIMIT_ONE);
        UserDO user = userService.getOne(queryWrapper);
        if (user == null) {
            return new ArrayList<>(0);
        }
        List<FunctionPermissionDO> permissionList;
        if (SysConstant.ADMIN.equals(user.getUsername())) {
            permissionList = permissionService.listAllPermissons();
        } else {
            permissionList = listUserAllPermissions(user.getId()).getFunctionPermissions();
            permissionList = (List<FunctionPermissionDO>) treeAssemblyUtils.getBaseTreeByGroup(permissionList);
        }
        return Optional.ofNullable(permissionList).orElse(new ArrayList<>(0));
    }


}
